/*
 * IShaderConstructor.cpp
 *
 *  Created on: 09.05.2012
 *      Author: Kirill Blinov
 *      Copyright: LGPL
 */

#include "CShaderConstructor.h"


CShaderConstructor::CShaderConstructor( std::string TypeName,
										GLuint ProgramName,
										std::vector<IShaderParamParser*> ParsersArray,
									    std::string LoadedShaderParameters,
									    std::vector< std::string > SortedShaderTextures ) :
	typeName(TypeName), programName(ProgramName), loadedShaderParameters(LoadedShaderParameters), parsersArray(ParsersArray),
	sortedShaderTextures( SortedShaderTextures )
{

}

CShaderConstructor::~CShaderConstructor()
{
}

bool
CShaderConstructor::ParseConfigurationString( std::string ConfigurationString, IShaderProgram *ShaderProgram )const
{
	std::string UnrecognizedTokens;
	size_t LastFoundPosition = 0;
	size_t FoundPosition = ConfigurationString.find( ";" );
	bool ParameterFound = true;

	while ( FoundPosition != std::string::npos )
	{
		std::string Parameter = ConfigurationString.substr( LastFoundPosition, FoundPosition - LastFoundPosition );

		size_t ParameterVariableStart = Parameter.find( ":" ) + 1; // +1 to miss ':' character
		size_t ParameterValueStart = Parameter.find( ":", ParameterVariableStart ) + 1;
		assert( ( ( ParameterVariableStart != std::string::npos ) && ( ParameterValueStart != std::string::npos ) ) );

		//Check if parameter was recognized
		bool ApplyResult = false;
		ParameterFound = false;
		// iterate over parsers
		for ( std::vector<IShaderParamParser*>::const_iterator Begin = parsersArray.begin(),
			  End = parsersArray.end();
			  Begin != End; Begin++ )
		{
			// If parameter is recognized stop iteration
			IShaderParamParser* ShaderParamParser = *Begin;
			ParameterFound = ShaderParamParser->TryToApplyParameter( ParameterVariableStart,
															  	  	 ParameterValueStart,
															  	  	 Parameter,
															  	  	 ShaderProgram,
															  	  	 sortedShaderTextures,
															  	  	 &ApplyResult );

			if ( ( ParameterFound ) || ( false == ApplyResult ) )
			{
				break;
			}
		}

		if ( !( ParameterFound && ApplyResult ) )
		{
			const char* ErrorMessage = ( !ParameterFound ) ? "Parser for shader parameter %s not found!\n" :
															  "Can't apply shader parameter: %s\n";
			fprintf( stderr, ErrorMessage, Parameter.c_str() );
		}

		LastFoundPosition = FoundPosition + 1;
		FoundPosition = ConfigurationString.find( ';', LastFoundPosition );
	}

	return ParameterFound;
}

IShaderProgram*
CShaderConstructor::ConstructShader( const std::string ConfigurationString )const
{
	IShaderProgram* NewShaderProgram = new CShaderProgram( programName );
	assert( NewShaderProgram );

	std::string UnitedParameres = loadedShaderParameters + ConfigurationString;
	bool ParseResult = ParseConfigurationString( UnitedParameres, NewShaderProgram );

	//Check for unrecognized parameters.
	if ( false == ParseResult )
	{
		delete NewShaderProgram;
		NewShaderProgram = NULL;
	}
	return NewShaderProgram;
}

